package com.wimcorp.magic.client.input;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.lang.StringUtils;
import org.fusesource.jansi.Ansi.Color;

import com.wimcorp.magic.client.CommandLineInterface;
import com.wimcorp.magic.exception.ManaException;
import com.wimcorp.magic.exception.SystemException;
import com.wimcorp.magic.input.BehaviorInput;
import com.wimcorp.magic.input.Location;
import com.wimcorp.magic.input.Type;
import com.wimcorp.magic.userinterface.GameInterface;

public abstract class Selector {

	private boolean run = true;
	private CommandLineInterface commandLineInterface;

	public Selector(CommandLineInterface commandLineInterface) {
		this.commandLineInterface = commandLineInterface;
	}


	protected Option getSelectOption(Set<String> types, Set<String> locations, Set<String> behaviors) {
		StringBuilder description = new StringBuilder("Select <id> ");
		description.append(getArrayString(types));
		if (behaviors.size() != 0) {
			description.append(" with ");
			description.append(getArrayString(behaviors));
		}
		if (locations.size() != 0) {
			if ("Battlefield".equals(getArrayString(locations))) {
				description.append(" on battlefield. ");
			} else {
				description.append(" in " + getArrayString(locations).toLowerCase());
				description.append(". ");
			}
		}
		Option option = new Option("s", "select", true, description.toString());
		option.setArgName("id");
		return option;
	}
	
	protected Option getActivateAbilitiesOption() {
		return new Option("aa", "activate-ability", false, "Activate an ability");
	}

	protected Option getDelcareAttackOption(Set<String> types, Set<String> locations) {
		StringBuilder description = new StringBuilder("Select <id> ");
		description.append(getArrayString(types));
		if (locations.size() != 0) {
			if ("Battlefield".equals(getArrayString(locations))) {
				description.append(" on battlefield. ");
			} else {
				description.append(" in " + getArrayString(locations).toLowerCase());
				description.append(". ");
			}
		}
		Option option = new Option("s", "select", true, description.toString());
		option.setArgName("id");
		return option;
	}

	protected Option getDelcareBlockerOption(Set<String> types, Set<String> locations) {
		StringBuilder description = new StringBuilder("Select <id> ");
		description.append(getArrayString(types));
		if (locations.size() != 0) {
			if ("Battlefield".equals(getArrayString(locations))) {
				description.append(" on battlefield. ");
			} else {
				description.append(" in " + getArrayString(locations).toLowerCase());
				description.append(". ");
			}
		}
		Option option = new Option("s", "select", true, description.toString());
		option.setArgName("id");
		return option;
	}

	protected Option getTapLandOption() {
		Option option = new Option("tl", "tap-land", true, "Tap land <id>");
		option.setArgName("id");
		option.setOptionalArg(true);
		option.setArgs(10);
		return option;
	}

	protected Option getUnTapLandOption() {
		Option option = new Option("utl", "untap-land", true, "Untap land <id>");
		option.setArgName("id");
		option.setOptionalArg(true);
		option.setArgs(10);
		return option;
	}
	
	protected Option getOrderInputOption() {
		Option option = new Option("o", "order", true, "Order id's <use ',' to seperate id's >");
		option.setArgName("id");
		return option;
	}

	protected Option getDoneOption() {
		return new Option("d", "done", false, "Done");
	}

	protected Option getHelpOption() {
		return new Option("h", "help", false, "List available commands. ");
	}

	protected Option getListAvailableDecksOption() {
		return new Option("l", "list", false, "List available decks");
	}

	protected Option getListColorsOption() {
		Option option = new Option("lc", "list-colors", false, "List available colors ");
		return option;
	}

	protected Option getMulliganOption() {
		return new Option("m", "mulligan", false, "Discard cards");
	}
	
	protected Option getTestOption() {
		return new Option("t", "test", false, "Start with test cards");
	}

	protected Option getPlayerListOption() {
		return new Option("lp", "players", false, "List players");
	}

	protected Option getReadyOption() {
		return new Option("r", "ready", false, "Ready");
	}

	protected Option getSelectOption() {
		Option option = new Option("s", "select", true, "Select <id>");
		option.setArgName("id");
		return option;
	}

	protected Option getSelectYesOption() {
		Option option = new Option("y", "yes", false, "Yes");
		return option;
	}

	protected Option getSelectNoOption() {
		Option option = new Option("n", "no", false, "No");
		return option;
	}

	protected Option getSelectColorOption() {
		Option option = new Option("s", "select-color", true, "Select <id>");
		option.setArgName("id");
		return option;
	}

	protected Option getSelectGraveyardCreatureOption() {
		Option option = new Option("s", "select-graveyard-creature", true, "Select <id>");
		option.setArgName("id");
		return option;
	}

	protected Option getSelectGraveyardCardOption() {
		Option option = new Option("s", "select-graveyard-card", true, "Select <id>");
		option.setArgName("id");
		return option;
	}

	protected Option getViewAttackersOption() {
		Option option = new Option("va", "view-attackers", false, "View attackers");
		return option;
	}

	protected Option getViewBattleFieldOption() {
		Option option = new Option("vb", "view-battlefield", true,
				"View the cards on the battlefield <optional player-name>");
		option.setOptionalArg(true);
		option.setArgName("player-name");
		return option;
	}
	
	protected Option getViewBlockersdOption() {
		Option option = new Option("vbl", "view-blockers", false,
				"View blockers");
		return option;
	}
	
	

	protected Option getViewGraveyardOption() {
		Option option = new Option("vg", "view-graveyard", true,
				"View the cards in the graveyard <optional player-name>");
		option.setOptionalArg(true);
		option.setArgName("player-name");
		return option;
	}

	protected Option getViewHandOption() {
		return new Option("vh", "view-hand", false, "View the cards in your hand. ");
	}

	protected Option getViewLifeOption() {
		Option option = new Option("vl", "view-life", true, "View Life <optional player-name>");
		option.setOptionalArg(true);
		option.setArgName("player-name");
		return option;
	}

	protected String getArrayString(Set<String> values) {
		StringBuilder result = new StringBuilder();
		int i = 0;
		for (String value : values) {
			i++;
			result.append(value);
			if (i != values.size()) {
				result.append(", ");
			}
		}
		return result.toString();
	}

	public long processCommands(Options options, Option[] commands) throws RemoteException, SystemException,
			ManaException {
		long result = -1;
		GameInterface game = commandLineInterface.getGame();
		String playerName = commandLineInterface.getPlayerName();
		for (Option option : commands) {
			if ("aa".equals(option.getOpt())) {
				game.activateAbility(playerName);
			}
			if ("d".equals(option.getOpt())) {
				run = false;
			}
			if ("h".equals(option.getOpt())) {
				HelpFormatter formatter = new HelpFormatter();
				formatter.printHelp("mtg", options);
			}
			if ("l".equals(option.getOpt())) {
				List<String> decks = game.viewAvailableDecks();
				for (String deck : decks) {
					commandLineInterface.print(deck, Color.WHITE);
				}
			}
			if ("lp".equals(option.getOpt())) {
				List<String> players = game.getPlayers();
				for (String player : players) {
					commandLineInterface.print(player, Color.WHITE);
				}
			}
			if ("m".equals(option.getOpt())) {
				commandLineInterface.print("You drew " + game.mulligan(playerName) + " new cards. ", Color.WHITE);
			}
			if ("r".equals(option.getOpt())) {
				game.ready(playerName);
				run = false;
			}
			if ("t".equals(option.getOpt())) {
				 game.testHand(playerName);
				 commandLineInterface.print("You cheated preselected cards. ", Color.WHITE);
			}
			if ("tl".equals(option.getOpt())) {
				for (String input : option.getValues()) {
					if (StringUtils.isNumeric(input)) {
						long identifier = new Long(input);
						Set<String> tapTypes = new HashSet<>();
						tapTypes.add(Type.LAND.toString());
						Set<String> tapLocations = new HashSet<>();
						tapLocations.add(Location.BATTLEFIELD.toString());
						Set<String> tapBehaviors = new HashSet<>();
						result = game.validateInput(playerName, tapTypes, tapLocations, tapBehaviors, identifier);
						if (result != -1) {
							game.tap(playerName, identifier);
						} else {
							throw new SystemException("No land with id " + input + " found. ");
						}
					}
				}
			}
			if ("utl".equals(option.getOpt())) {
				for (String input : option.getValues()) {
					if (StringUtils.isNumeric(input)) {
						long identifier = new Long(input);
						Set<String> tapTypes = new HashSet<>();
						tapTypes.add(Type.LAND.toString());
						Set<String> tapLocations = new HashSet<>();
						tapLocations.add(Location.BATTLEFIELD.toString());
						Set<String> tapBehaviors = new HashSet<>();
						tapBehaviors.add(BehaviorInput.TAPPED.toString());
						result = game.validateInput(playerName, tapTypes, tapLocations, tapBehaviors, identifier);
						if (result != -1) {
							game.untap(playerName, identifier);
						} else {
							throw new SystemException("No land with id " + input + " is tapped. ");
						}
					}
				}
			}
			if ("va".equals(option.getOpt())) {
				List<String> cards = new ArrayList<>();
				cards = game.viewAttackers();
				for (String deck : cards) {
					commandLineInterface.print(deck, Color.WHITE);
				}
			}
			if ("vb".equals(option.getOpt())) {
				List<String> cards = new ArrayList<>();
				String name = option.getValue();
				if (name == null) {
					cards = game.viewBattlefield();
				} else {
					if (game.playerExists(name)) {
						cards = game.viewBattlefield(name);
					} else {
						throw new SystemException("Player with name : " + name + " not found. ");
					}
				}
				for (String deck : cards) {
					commandLineInterface.print(deck, Color.WHITE);
				}
			}
			if ("vd".equals(option.getOpt())) {
				List<String> cards = game.viewDeck(playerName);
				for (String deck : cards) {
					commandLineInterface.print(deck, Color.WHITE);
				}
			}
			if ("vg".equals(option.getOpt())) {
				List<String> cards = new ArrayList<>();
				String name = option.getValue();
				if (name == null) {
					cards = game.viewGraveyard(playerName);
				} else {
					if (game.playerExists(name)) {
						cards = game.viewGraveyard(name);
					} else {
						throw new SystemException("Player with name : " + name + " not found. ");
					}
				}
				for (String deck : cards) {
					commandLineInterface.print(deck, Color.WHITE);
				}
			}
			if ("ve".equals(option.getOpt())) {
				List<String> cards = new ArrayList<>();
				String name = option.getValue();
				if (name == null) {
					cards = game.viewExile(playerName);
				} else {
					if (game.playerExists(name)) {
						cards = game.viewExile(name);
					} else {
						throw new SystemException("Player with name : " + name + " not found. ");
					}
				}
				for (String deck : cards) {
					commandLineInterface.print(deck, Color.WHITE);
				}
			}
			if ("vh".equals(option.getOpt())) {
				List<String> cards = game.viewHand(playerName);
				for (String deck : cards) {
					commandLineInterface.print(deck, Color.WHITE);
				}
			}
			if ("vl".equals(option.getOpt())) {
				int life = 0;
				String name = option.getValue();
				if (name == null) {
					life = game.viewLife(playerName);
				} else {
					if (game.playerExists(name)) {
						life = game.viewLife(name);
					} else {
						throw new SystemException("Player with name : " + name + " not found. ");
					}
				}
				commandLineInterface.print("" + life, Color.WHITE);

			}
		}
		return result;
	}

	public boolean isRun() {
		return run;
	}

	public void setRun(boolean run) {
		this.run = run;
	}

	public CommandLineInterface getCommandLineInterface() {
		return commandLineInterface;
	}

}
